package com.cfp4cloud.cfp.knowledge.support.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * HTTP请求日志拦截器
 * <p>
 * 实现ClientHttpRequestInterceptor接口，用于记录HTTP请求和响应的详细信息。 主要用于调试和问题排查，可以查看完整的请求/响应内容
 * </p>
 *
 * @author chenda
 * @date 2024/4/24
 */
@Slf4j
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

	/**
	 * 默认构造函数
	 */
	public LoggingRequestInterceptor() {
	}

	/**
	 * 拦截HTTP请求，记录请求和响应的详细信息
	 * @param request 客户端HTTP请求对象
	 * @param body 请求体字节数组
	 * @param execution 请求执行器，用于执行实际的HTTP请求
	 * @return HTTP响应对象
	 * @throws IOException 当请求执行或日志记录过程中发生IO异常时抛出
	 */
	public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
			throws IOException {
		// 记录请求信息
		traceRequest(request, body);
		// 执行请求
		ClientHttpResponse response = execution.execute(request, body);
		// 记录响应信息
		traceResponse(response);
		return response;
	}

	/**
	 * 记录HTTP请求的详细信息
	 * @param request HTTP请求对象
	 * @param body 请求体字节数组
	 * @throws IOException 当记录日志时发生IO异常
	 */
	private void traceRequest(HttpRequest request, byte[] body) throws IOException {
		log.info("===========================request begin================================================");
		log.info("URI         : {}", request.getURI());
		log.info("Method      : {}", request.getMethod());
		log.info("Headers     : {}", request.getHeaders());
		log.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
		log.info("==========================request end================================================");
	}

	/**
	 * 记录HTTP响应的详细信息
	 * @param response HTTP响应对象
	 * @throws IOException 当读取响应内容时发生IO异常
	 */
	private void traceResponse(ClientHttpResponse response) throws IOException {
		log.info("============================response begin==========================================");
		log.info("Status code  : {}", response.getStatusCode());
		log.info("Status text  : {}", response.getStatusText());
		log.info("Headers      : {}", response.getHeaders());
		// 响应体内容使用debug级别记录，避免在生产环境中输出过多日志
		log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8));
		log.info("=======================response end=================================================");
	}

}
